package dataDraw.classDiagramDraw;

import data.DataVector;
import data.Position;
import data.classDiagram.ClassEntity;
import data.classDiagram.Entity;
import data.classDiagram.Member;
import dataDraw.Constants;
import dataDraw.TextDraw;

import java.awt.*;

/**
 * User: Szymon Kudzia
 * Date: 22.04.13
 * Time: 18:23
 */
public class BasicEntityConnectionDraw implements EntityConnectionDraw {
	TextDraw textDraw;
	Graphics g;

	public void draw(Entity entity, Graphics graphics) {
		g = graphics;
		textDraw.setGraphics(g);

		if (entity instanceof ClassEntity) {
			ClassEntity classEntity = (ClassEntity) entity;
			if (!classEntity.getBaseClass().isEmpty()) {
				Entity baseClass = DataVector.getInstance().findEntity(classEntity.getBaseClass());
				if (null != baseClass) {
					drawExtendConnection(entity, baseClass);
				}
			}
		}

		for (String interfaceName : entity.getInterfacesImplemented()) {
			Entity baseInterface = DataVector.getInstance().findEntity(interfaceName);
			if (null != baseInterface) {
				drawExtendConnection(entity, baseInterface);
			}
		}

		for (Member member : entity.getMembers()) {
			Entity typeEntity = DataVector.getInstance().findEntity(member.getType());
			if (null != typeEntity) {
				member.getPosition().setWidth(entity.getPosition().getWidth());
				drawMemberConnection(member, typeEntity);
			}

		}
	}

	protected void drawExtendConnection(Entity derived, Entity base) {
		Position derivedPos = derived.getPosition();
		Position basePos = base.getPosition();

		if (basePos.isBelow(derivedPos)) {
			drawExtendHorizontalConnection(derivedPos.getMiddleDown(), basePos.getMiddleUp());
		} else if (derivedPos.isBelow(basePos)) {
			drawExtendHorizontalConnection(derivedPos.getMiddleUp(), basePos.getMiddleDown());
		} else if (derivedPos.isLeft(basePos)) {
			drawExtendVerticalConnection(derivedPos.getRightMiddle(), basePos.getLeftMiddle());
		} else if (derivedPos.isRight(basePos)) {
			drawExtendVerticalConnection(derivedPos.getLeftMiddle(), basePos.getRightMiddle());
		}
	}

	protected void drawExtendHorizontalConnection(tools.Point p1, tools.Point p2) {
		int y_before_triangle = 0;
		if (p1.y > p2.y) {
			y_before_triangle = p2.y + Constants.TRIANGLE_H;
		} else {
			y_before_triangle = p2.y - Constants.TRIANGLE_H;
		}

		drawHorizontalConnection(p1, new tools.Point(p2.x, y_before_triangle));

		//draw triangle
		drawHorizontalTriangle(p2, y_before_triangle);
	}

	protected void drawHorizontalTriangle(tools.Point p2, int y_before_triangle) {
		g.drawLine(p2.x - Constants.TRIANGLE_HALF_A, y_before_triangle, p2.x + Constants.TRIANGLE_HALF_A, y_before_triangle);
		g.drawLine(p2.x - Constants.TRIANGLE_HALF_A, y_before_triangle, p2.x, p2.y);
		g.drawLine(p2.x + Constants.TRIANGLE_HALF_A, y_before_triangle, p2.x, p2.y);
	}

	protected void drawExtendVerticalConnection(tools.Point p1, tools.Point p2) {
		int x_before_triangle = 0;
		if (p1.x > p2.x) {
			x_before_triangle = p2.x + Constants.TRIANGLE_H;
		} else {
			x_before_triangle = p2.x - Constants.TRIANGLE_H;
		}

		drawVerticalConnection(p1, new tools.Point(x_before_triangle, p2.y));

		//draw triangle
		drawVerticalTriangle(p2, x_before_triangle);
	}

	protected void drawVerticalTriangle(tools.Point p2, int x_before_triangle) {
		g.drawLine(x_before_triangle, p2.y - Constants.TRIANGLE_HALF_A, x_before_triangle, p2.y + Constants.TRIANGLE_HALF_A);
		g.drawLine(x_before_triangle, p2.y - Constants.TRIANGLE_HALF_A, p2.x, p2.y);
		g.drawLine(x_before_triangle, p2.y + Constants.TRIANGLE_HALF_A, p2.x, p2.y);
	}

	private void drawMemberConnection(Member member, Entity typeEntity) {
		Position memberPos = member.getPosition();
		Position typeEntityPos = typeEntity.getPosition();

		tools.Point p_rhomb = null;
		if (memberPos.getMiddleX() < typeEntityPos.getMiddleX()) {
			p_rhomb = drawRightRhomb(memberPos.getRightMiddle());
		} else {
			p_rhomb = drawLeftRhomb(memberPos.getLeftMiddle());
		}

		if (memberPos.isLeft(typeEntityPos)) {
			drawMemberVerticalConnection(p_rhomb, typeEntityPos.getLeftMiddle(), member.getMinMax());
		} else if (memberPos.isRight(typeEntityPos)) {
			drawMemberVerticalConnection(p_rhomb, typeEntityPos.getRightMiddle(), member.getMinMax());
		} else if (memberPos.isBelow(typeEntityPos)) {
			drawMemberHorizontalConnection(p_rhomb, typeEntityPos.getMiddleDown(), member.getMinMax());
		} else if (memberPos.isAbove(typeEntityPos)) {
			drawMemberHorizontalConnection(p_rhomb, typeEntityPos.getMiddleUp(), member.getMinMax());
		}
	}

	protected tools.Point drawRightRhomb(tools.Point p) {
		g.drawLine(p.x, p.y, p.x + Constants.RHOMB_H1, p.y - Constants.RHOMB_H2);
		g.drawLine(p.x, p.y, p.x + Constants.RHOMB_H1, p.y + Constants.RHOMB_H2);
		g.drawLine(p.x + Constants.RHOMB_H1, p.y - Constants.RHOMB_H2, p.x + 2 * Constants.RHOMB_H1, p.y);
		g.drawLine(p.x + Constants.RHOMB_H1, p.y + Constants.RHOMB_H2, p.x + 2 * Constants.RHOMB_H1, p.y);

		return new tools.Point(p.x + 2 * Constants.RHOMB_H1, p.y);
	}

	protected tools.Point drawLeftRhomb(tools.Point p) {
		g.drawLine(p.x, p.y, p.x - Constants.RHOMB_H1, p.y - Constants.RHOMB_H2);
		g.drawLine(p.x, p.y, p.x - Constants.RHOMB_H1, p.y + Constants.RHOMB_H2);
		g.drawLine(p.x - Constants.RHOMB_H1, p.y - Constants.RHOMB_H2, p.x - 2 * Constants.RHOMB_H1, p.y);
		g.drawLine(p.x - Constants.RHOMB_H1, p.y + Constants.RHOMB_H2, p.x - 2 * Constants.RHOMB_H1, p.y);

		return new tools.Point(p.x - 2 * Constants.RHOMB_H1, p.y);
	}

	private void drawMemberVerticalConnection(tools.Point p1, tools.Point p2, String minMax) {
		drawVerticalConnection(p1, p2);
		tools.Point minMaxSize = new tools.Point(g.getFontMetrics().stringWidth(minMax),
												 g.getFontMetrics().getHeight());

		Position position = new Position();
		position.setY(p2.y - minMaxSize.y - Constants.MARGIN);

		if (p1.x < p2.x) {
			position.setX(p2.x - minMaxSize.x);
		} else {
			position.setX(p2.x);
		}

		//textDraw.drawString(minMax, position);
	}

	private void drawMemberHorizontalConnection(tools.Point p1, tools.Point p2, String minMax) {
		drawHorizontalConnection(p1, p2);
		tools.Point minMaxSize = new tools.Point(g.getFontMetrics().stringWidth(minMax),
												 g.getFontMetrics().getHeight());

		Position position = new Position();
		position.setX(p2.x);

		if (p1.y < p2.y) {
			position.setY(p2.y - minMaxSize.y - Constants.MARGIN);
		} else {
			position.setY(p2.y + Constants.MARGIN);
		}

		//textDraw.drawString(minMax, position);
	}




	protected void drawVerticalConnection(tools.Point p1, tools.Point p2) {
		int middle = (p1.x + p2.x) / 2;
		g.drawLine(p1.x, p1.y, middle, p1.y);
		g.drawLine(middle, p1.y, middle, p2.y);
		g.drawLine(middle, p2.y, p2.x, p2.y);
	}

	protected void drawHorizontalConnection(tools.Point p1, tools.Point p2) {
		int middle = (p1.y + p2.y) / 2;
		g.drawLine(p1.x, p1.y, p1.x, middle);
		g.drawLine(p1.x, middle, p2.x, middle);
		g.drawLine(p2.x, middle, p2.x, p2.y);
	}

	public void setTextDraw(TextDraw textDraw) {
		this.textDraw = textDraw;
	}
}
